//var tronWeb; //tronWeb对象 //这里不需要这个
//var sender = "TNaRAoLUyYEV2uF7GUrzSjRQTU8v5ZJ5VR"; //初始化用户地址 //T搬到store

import { getUrlParam, toNonExponential } from '@/libs/site.utils';


export const CALLBACK_ERR = "NAN"; //请求异常 回调函数返回数据
export const RELATION_HOST = "https://server.xgame.run/";//用户推荐关系请求服务器
export const PAGE_SIZE = 10;//分页请求数量
export const RELATION_CONTRACT_ADDRESS = "TGiXT5bR9ZYkCtdhKFkHQLvEY2M3P1HwRq";//关系合约地址

const TRANSACTION_INFO_REFRESH_DELAY = 5000; //交易信息读取刷新频率
const BLOCK_CONFIRMED_REFRESH_DELAY = 15000; //区块确认数据刷新周期 15秒

/**
 * 用于某些地方是否显示console.log, 由于后面可能还要调试，所以用这个方式
 * 但注意有个移除console.log的插件，可能会出问题
 */
export const dev = process.env.NODE_ENV === 'development' ? true : false; //开发模式才为true

/*
* 各数据页面初始化数据延迟加载时间，为什么要延迟加载 ？因为tronWeb对象可能未初始化完成
* */
export const INITDATA_TIME_LIMIT = 2000;


/**************************************************************************************
 *                               挖矿相关请求接口                                  	  *
 ***************************************************************************************/

/************************************
 * 									*
 * 								  	*
 * 								  	*
 *           常量合约				*
 *  产生的交易不上链，不消耗手续费		*
 * 									*
 * 									*
 * 									*
 * **********************************
 */


/**
 * @description  查询代币总共释放数量
 * @param {Object} contract 合约地址
 * @param {Object} sender 发送方地址
 * @param {Object} callback 回调函数
 */
export function totalRelease (contract, sender, callback) {
    let parameters = [];
    let func = "supply()";
    trigerConstantContract(contract, func, parameters, sender, callback);
}


/**
 * @description  查询代币当前流通总量
 * @param {Object} contract 合约地址
 * @param {Object} sender 发送方地址
 * @param {Object} callback 回调函数
 */
export function totalSupply (contract, sender, callback) {
    let parameters = [];
    let func = "totalSupply()";
    trigerConstantContract(contract, func, parameters, sender, callback);
}


/**
 * @description  查询代币当前销毁总量
 * @param {Object} contract
 * @param {Object} sender
 * @param {Object} callback
 */
export function totalBurned (contract, sender, callback) {
    let parameters = [];
    let func = "totalBurned()";
    trigerConstantContract(contract, func, parameters, sender, callback);

}

/**
 * @description  查询用户持有代币数量
 * @param {Object} contract 代币合约地址
 * @param {Object} sender 用户地址
 * @param {Object} callback 回调函数
 */
export function balanceOf (contract, sender, callback) {
    let parameters = [{
        type: "address",
        value: sender
    }];
    let func = "balanceOf(address)";
    trigerConstantContract(contract, func, parameters, sender, callback);
}


//	授权额度查询
export function allowance(token, contract, sender ,cb) {
    let parameters = [{
        type: 'address',
        value: sender
    }, {
        type: 'address',
        value: contract
    }];
    let func = "allowance(address,address)";
    trigerConstantContract(token, func , parameters , sender , (res)=>{
        cb(res);
    });
}


/**
 * @description  查询用户defi矿池当前可收获数量
 * @param {Object} contract 矿池合约地址
 * @param {Object} sender 用户地址
 * @param {Object} callback 回调函数
 */
export function earned (contract, sender, callback) {
    let parameters = [{
        type: "address",
        value: sender
    }];
    let func = "earned(address)";
    trigerConstantContract(contract, func, parameters, sender, callback);
}


/**
 * @description  获取矿池信息
 * @param {Object} pool 矿池地址
 * @param {Object} sender 用户地址
 * @param {Object} callback 回调函数
 */
export function getInfoAll2 (pool, sender, callback) {
    let parameters = [{
        type: "address",
        value: sender
    }, {
        type: "address[]",
        value: ["41" +tronWeb.address.toHex(pool).substring(2)]
    }];
    let func = "getInfoAll2(address,address[])";
    trigerConstantContract("TDQ6peySpWnmArP4Je8XXBp54j4h4vtzym", func, parameters, sender, callback);
}


/**
 * @description 官方提供的获取矿池apy的接口(数据延迟严重，不建议使用)
 * @param {Object} type 锁仓币种类型 0:lp 1:token 2:trx
 * @param {Object} pool 矿池合约地址
 * @param {Object} sender 用户地址
 * @param {Object} callback 回调函数
 */
export function fetchApy (type, pool, sender, callback) {
    let parameters = [{
        type: "address",
        value: pool
    }];
    let func = "";
    switch (type) {
        case 0: //lp
        default:
            func = "fetchAPYofLpPool(address)";
            break;
        case 1: //token
            func = "fetchAPYofTokenPool(address)";
            break;
        case 2: //trx
            func = "fetchAPYofTrx(address)";
            break;
    }
    trigerConstantContract("TDQ6peySpWnmArP4Je8XXBp54j4h4vtzym", func, parameters, sender, callback);
}



/**
 * @description  获取用户矿池锁仓币种数量 以及 对于次矿池的授权数量
 * @param {Object} token 矿池锁仓币种
 * @param {Object} pool 矿池合约地址
 * @param {Object} sender 用户地址
 * @param {Object} callback 回调函数
 */
export function getBalanceAndApprove2 (token, pool, sender, callback) {
    let parameters = [{
        type: "address",
        value: sender
    }, {
        type: "address[]",
        value: ["41" + tronWeb.address.toHex(token).substring(2)]
    }, {
        type: "address[]",
        value: ["41" + tronWeb.address.toHex(pool).substring(2)]
    }];
    let func = "getBalanceAndApprove2(address,address[],address[])";
    trigerConstantContract("TDQ6peySpWnmArP4Je8XXBp54j4h4vtzym", func, parameters, sender, callback);
}


/**
 * @description  获取trx兑换token的价格 [接口描述请参考justswap.io的开发者文档]
 * @param {Object} pairAddress 交易对合约地址
 * @param {Object} sender 用户地址
 * @param {Object} amount 兑换的token数量
 * @param {Object} callback 回调函数
 */
export function getTrxToTokenOutputPrice (pairAddress, sender, amount, callback) {
    let parameters = [{
        type: "uint256",
        value: amount
    }];
    let func = "getTrxToTokenOutputPrice(uint256)"; //买入价
    trigerConstantContract(pairAddress, func, parameters, sender, callback);
}




/**
 * @description  计算未释放量
 * @param {Object} start 开始时间 秒
 * @param {Object} end 结束时间 秒
 * @param {Object} total 总共数量
 */
export function getAllocatable (start, end, total) {
    if (start > end) {
        return 0
    }
    let mills = new Date().getTime() / 1000;
    if (mills >= end) {
        return 0;
    } else if (mills <= start) {
        return total;
    } else {
        return total * (end - mills) / (end - start);
    }
}



/**
 * @description  计算矿池年华
 * @param {Object} total 矿池总释放量
 * @param {Object} start 开始时间 秒
 * @param {Object} end 结束时间 秒
 * @param {Object} price 代币价格(usdt)
 * @param {Object} lockValue 锁仓总价值(usdt)
 */
export function caculateApy (total, start, end, price, lockValue) {
    if (price === 0) {
        return "NaN";
    }
    if (parseFloat(lockValue) === 0) {
        return "NaN";
    }
    let year = 365 * 24 * 60 * 60;
    let per_second_reward_num = total / (end - start);
    let per_second_reward_value = per_second_reward_num * price;
    let apy = per_second_reward_value * year / lockValue;
    apy = toNonExponential(new Number(apy * 100));
    return parseFloat(apy).toFixed(2);
}






/************************************
 * 									*
 * 								  	*
 * 								  	*
 *           智能合约				*
 *  产生的交易上链，消耗手续费			*
 * 									*
 * 									*
 * 									*
 * **********************************
 */


/**
 * @description  授权
 * @param {Object} pool 矿池合约地址
 * @param {Object} token 授权币种地址
 * @param {Object} sender 用户地址
 * @param {Object} callback 回调函数
 * @param {Object} confirmCallback 区块确认回调函数
 */
export function approve (pool, token, sender, callback, confirmCallback) {
    let parameters = [{
        type: 'address',
        value: pool
    }, {
        type: 'uint256',
        value: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
    }];
    let func = "approve(address,uint256)";
    trigerSmartContract(token, func, parameters, sender, callback, confirmCallback);
}


/**
 * @description  锁定挖矿[非trx代币]
 * @param {Object} pool 矿池合约地址
 * @param {Object} sender 用户地址
 * @param {Object} amount 锁定数量
 * @param {Object} decimal 锁定币种精度
 * @param {Object} callback 回调函数
 * @param {Object} confirmCallback 区块确认回调函数
 */
export function stake (pool, sender, amount, decimal, callback, confirmCallback) {
    if (typeof decimal === "undefined") {
        decimal = 6;
    }
    amount = amount * Math.pow(10, decimal);
    amount = amount.toFixed(0); //修复js
    let parameters = [{
        type: "uint256",
        value: amount
    }];
    let func = "stake(uint256)";
    trigerSmartContract(pool, func, parameters, sender, callback, confirmCallback);
}


/**
 * @description  锁定挖矿 trx代币
 * @param {Object} pool 矿池合约地址
 * @param {Object} sender 用户地址
 * @param {Object} amount 锁定数量
 * @param {Object} decimal trx代币精度
 * @param {Object} callback 回调函数
 * @param {Object} confirmCallback 区块确认回调函数
 */
export function stakeTrx (pool, sender, amount, decimal, callback, confirmCallback) {
    if (typeof decimal === "undefined") {
        decimal = 6;
    }
    amount = amount * Math.pow(10, decimal);
    amount = amount.toFixed(0); //修复js
    let func = "stake()";
    let callValue = {
        callValue: amount
    };
    tronWeb.transactionBuilder.triggerSmartContract(tronWeb.address.toHex(pool),
        func, callValue, [], sender).then(tradeobj => {
        tronWeb.trx.sign(tradeobj.transaction).then(signedtxn => {
            tronWeb.trx.sendRawTransaction(signedtxn).then(receipt => {
                if (receipt && receipt.result) { //广播成功
                    let txid = receipt.txid;
                    callback(1, txid);
                    console.log("交易txid:" + txid);
                    getConfirmedTransaction(txid, confirmCallback);
                } else { //广播失败
                    console.log("广播失败");
                    callback(0);
                }
            }).catch(err => { //广播失败
                console.log("广播失败");
                callback(0);
            })
        }).catch(err => {
            if (err === "Confirmation declined by user") {
                console.log("取消");
                callback(-1);
            } else {
                callback(0);
            }
        });
    }).catch(err => {
        console.log("交易失败" + err);
    });

}



/**
 * @description  收获
 * @param {Object} pool 矿池合约地址
 * @param {Object} sender 用户地址
 * @param {Object} amount 数量 [参数未使用]
 * @param {Object} decimal 精度 [参数未使用]
 * @param {Object} callback 回调函数
 * @param {Object} confirmCallback 区块确认回调函数
 */
export function getReward (pool, sender, amount, decimal, callback, confirmCallback) {
    let parameters = [];
    let func = "getReward()";
    trigerSmartContract(pool, func, parameters, sender, callback, confirmCallback);
}

/**
 * @description  解锁并收获
 * @param {Object} pool 矿池合约地址
 * @param {Object} sender 用户地址
 * @param {Object} amount 解锁数量
 * @param {Object} decimal 解锁币种精度
 * @param {Object} callback 回调函数
 * @param {Object} confirmCallback 区块确认回调函数
 */
export function withdrawAndGetReward (pool, sender, amount, decimal, callback, confirmCallback) {
    if (typeof decimal === "undefined") {
        decimal = 6;
    }
    amount = amount * Math.pow(10, decimal);
    amount = amount.toFixed(0); //修复js
    let parameters = [{
        type: "uint256",
        value: amount
    }];
    let func = "withdrawAndGetReward(uint256)";
    trigerSmartContract(pool, func, parameters, sender, callback, confirmCallback);
}

/**
 * @description  退出 [矿池结束时，执行方法]
 * @param {Object} pool  矿池合约地址
 * @param {Object} sender 用户地址
 * @param {Object} callback 回调函数
 * @param {Object} confirmCallback 区块确认回调函数
 */
export function exit (pool, sender, callback, confirmCallback) {
    let parameters = [];
    let func = "exit()";
    trigerSmartContract(pool, func, parameters, sender, callback, confirmCallback);
}












/**************************************************************************************
 *                               推荐相关请求接口                                  	  *
 ***************************************************************************************/


/**
 *@description 获取用户推荐码
 * @param {Object} address 用户地址
 * @param {Object} callback 回调函数
 */
export function loadAuthInfo (address, callback) {
    $.ajax({
        url: RELATION_HOST + 'UserCenter?act=auth&reciptAddress=' + address,
        type: "POST",
        dataType: "JSON",
        data: {
            _t: Math.round(new Date().getTime() / 1000)
        }
    }).done(function (res) {
        if (res.resultFlag == true) {
            bindRelation(address); //绑定关系
            if (typeof callback === "function") {
                callback(res.shareCode);
            }
        }
    })
}


/**
 * @description  记录用户推荐关系
 * @param {Object} address 用户地址
 */
export function bindRelation (address) {
    let shareCode = getUrlParam("code"); //地址栏解析出的推荐码
    if (shareCode) {
        $.ajax({
            url: RELATION_HOST + 'UserCenter?act=bindRelation&shareCode=' + shareCode + '&reciptAddress=' + address,
            type: "POST",
            dataType: "JSON",
            data: {
                _t: Math.round(new Date().getTime() / 1000)
            }
        }).done(function (res) { //提交成功

        })
    }
}


/**
 * @description  获取推荐列表
 * @param {Object} address 关系合约地址
 * @param {Object} page 页码
 * @param {Object} size 页长
 * @param {Object} callback 回调函数
 */
export function getRelationList (params, callback) {
    if (!params.pageSize) {
	    params.pageSize = PAGE_SIZE;
    }
    $.ajax({
        // url: RELATION_HOST + 'UserCenter?act=listRelation&intrAddress=' + address + '&pageNo=' + page + '&pageSize=' + size,
        url: RELATION_HOST + 'UserCenter?act=listRelation',
	    // url:'http://rest.apizza.net/mock/3aa15ade9ab2add11fbd6b3a4f24a943/UserCenterlistRelation',
        type: "GET",
        dataType: "JSON",
        data: {
            _t: Math.round(new Date().getTime() / 1000),
	        ...params
        }
    }).done(function (res) {
        if (typeof callback === "function") {
            callback(res);
        }
    });
}


/**
 * @description  推荐关系上链
 * @param {Object} intr 推荐人
 * @param {Object} recipt 接收人
 * @param {Object} callback 回调函数
 */
export function activeRelationToChain (intr, recipt, callback) {
    let parameters = [{
        type: "address",
        value: intr
    }, {
        type: "address",
        value: recipt
    }];
    let func = "addRelation(address,address)";
    let sender = intr
    trigerSmartContract(RELATION_CONTRACT_ADDRESS, func, parameters, sender, (status, txid) => {
        if (status == 1) {
            activeRelation(intr, recipt, callback);
        }
    });
}

/**
 * @description  激活推荐记录
 * @param {Object} intr 推荐人
 * @param {Object} recipt 接收人
 * @param {Object} callback 回调函数
 */
export function activeRelation (intr, recipt, callback) {
    $.ajax({
        url: RELATION_HOST + 'UserCenter?act=activeRelation&intrAddress=' + intr + '&reciptAddress=' + recipt,
        type: "POST",
        dataType: "JSON",
        data: {
            _t: Math.round(new Date().getTime() / 1000)
        }
    }).done(function (res) {
        if (res.resultFlag == true) {
            if (typeof callback === "function") {
                callback(true);
            }
        }
    })
}



/**
 *
 * @description 调用常量合约[产生的交易不上链,不消耗手续费] 通用接口
 * @param {Object} contract 合约地址
 * @param {Object} func 访问abi接口
 * @param {Object} parameters 参数
 * @param {Object} sender 请求发送方地址
 * @param {Object} callback 回调函数
 */
export function trigerConstantContract (contract, func, parameters, sender, callback) {
	tronWeb.transactionBuilder.triggerConstantContract(tronWeb.address.toHex(contract),
		func, {}, parameters, sender).then(tradeobj => {
		if (tradeobj && tradeobj.result) {
			doCallback(callback, tradeobj.constant_result[0]);
		} else {
			doCallback(callback, CALLBACK_ERR);
		}

	}).catch(err => {
		doCallback(callback, CALLBACK_ERR);
		console.error(func + " " + contract + "异常:" + err);
	});
}



/**
 * //由于狗日trx让调了一倍手续费，这个方法默认上限是150个，手动加入这个参数为500trx
 * @description  调用合约非常量方法[产生的交易会上链，且消耗手续费] 通用接口
 * >>>>>>>>>>  注意，返回的状态码只是提交的结果，并不代表交易完成  <<<<<<<<<<<<<<<<<<<
 * @param {Object} contract 合约地址
 * @param {Object} func 访问abi接口
 * @param {Object} parameters 参数
 * @param {Object} sender 请求发送方地址
 * @param {Object} callback 回调函数
 * @param {Object} confirmCallback 交易确认后的回调函数
 */
export function trigerSmartContract (contract, func, parameters, sender, callback, confirmCallback) {
    tronWeb.transactionBuilder.triggerSmartContract(tronWeb.address.toHex(contract),
        func, 500000000,0, parameters, sender).then(tradeobj => {
        tronWeb.trx.sign(tradeobj.transaction).then(signedtxn => {
            tronWeb.trx.sendRawTransaction(signedtxn).then(receipt => {
                if (receipt && receipt.result) { //广播成功
                    let txid = receipt.txid;
                    doCallback(callback, 1, txid);
                    console.debug("交易txid:" + txid);
                    if (typeof confirmCallback === "function") {
                        getConfirmedTransaction(txid, confirmCallback);
                    }
                } else { //广播失败
                    console.debug("广播失败");
                    doCallback(callback, 0);
                }
            }).catch(err => { //广播失败
                console.debug("广播失败");
                doCallback(callback, 0);
            })
        }).catch(err => {
            if (err === "Confirmation declined by user") {
                console.debug("用户取消");
                doCallback(callback, -1);
            } else {
                doCallback(callback, 0);
            }
        });
    }).catch(err => {
        console.error("交易失败:" + err);
        doCallback(callback, 0);
    });
}




/**
 * @description  查询交易是否确认
 * @param {Object} txid 交易txid
 * @param {Object} callback 回调函数
 */
export function getConfirmedTransaction (txid, callback) {
    let interval = setInterval(() => {
        console.log('定时查询交易是否确认>>>>>>>>>>>>>>>>>>>>>')
        tronWeb.trx.getConfirmedTransaction(txid).then(result => {
            if (result) {
                clearInterval(interval);
                let status = result.ret[0].contractRet;
                doCallback(callback, txid, status);
                if (status === "SUCCESS") {
                    console.debug("区块已确认，且交易成功");
                } else {
                    console.debug("区块已确认,且交易失败");
                }
            }
        }).catch(err => { //区块未确认
            if (err != "Transaction not found") {
                console.error("获取区块确认出错:" + err);
                doCallback(callback, CALLBACK_ERR);
            }

        });
    }, BLOCK_CONFIRMED_REFRESH_DELAY);

}

/**
 * @description  获取交易信息
 * @param {Object} txid
 * @param {Object} callback
 */
export function getTransactionInfo (txid, callback, intervalMills) {
    if (!intervalMills) {
        intervalMills = TRANSACTION_INFO_REFRESH_DELAY;
    }
    let isConn = false;
    let interval = setInterval(() => {
        if (!isConn) {
            isConn = true;
            tronWeb.trx.getUnconfirmedTransactionInfo(txid).then(result => {
                isConn = false;
                if (result && result.receipt.result) {
                    clearInterval(interval);
                    let status = result.receipt.result;
                    if (status === 'SUCCESS') {
                        status = 1;
                        doCallback(callback, status, result.contractResult[0]);
                    } else {
                        status = 0;
                        doCallback(callback, status, CALLBACK_ERR);
                    }

                }
            }).catch(err => {
                //还未出块 如何处理？

            })
        }
    }, intervalMills);
}




/**
 * @description  将bytes系列参数转换为预提交所需格式
 * @param {Object} itemId 游戏选项
 * @param {Object} serise bytes系列长度 eg:bytes32 则填32
 */
export function formatBytes (itemId, serise) {
    serise = serise > 32 ? 32 : serise < 0 ? 0 : serise;
    let _hex = tronWeb.toHex(itemId).substring(2);
    let _length = serise * 2 - _hex.length;
    while (_length > 0) {
        _hex += "0";
        _length--;
    }
    return "0x" + _hex;
}

/**
 * @description  将hex数据转换为utf8
 * @param {Object} hex
 */
export function hex2Utf8 (hex) {
    return tronWeb.toUtf8("0x" + hex.replace(/00/g, ""));
}

/**
 * @description  将hex数据转换为对应精度的10进制数
 * @param {Object} hex
 * @param {Object} precision
 */
export function hex2Num (hex, precision) {
    return toNonExponential(tronWeb.toBigNumber("0x" + hex)) / Math.pow(10, precision);

}


/**
 * @description  执行回调函数
 * @param {Object} _callback 回调函数
 * @param {Object} ...params 不定参数
 */
export function doCallback (_callback, ...params) {
    if (typeof _callback === "function") {
        _callback(...params);
    }

}
